Матч 334, Террористы (Terrorists)

Дивизион 1, Уровень 3

 

Между каждой парой городов страны имеется прямая двусторонняя дорога. Террористы хотят взорвать такое количество дорог, чтобы образовалось хотя бы два города, проезд между которыми был невозможен.

Элемент roads[i][j] содержит стоимость подрыва дороги, ведущей из i - го города в j - ый. Найти наименьшую стоимость, за которую террористам удастся совершить задуманное.

 

Класс: Terrorists

Метод: int requiredCost(vector<string> roads)

Ограничения: roads содержит от 2 до 50 элементов, roads[i] содержат одинаковое количество символов, которыми являются цифры от 0 до 9, roads[i][i] = 0, roads[i][j] = roads[j][i].

 

Вход. Массив строк roads, описывающий стоимость подрыва дорог.

 

Выход. Наименьшая стоимость, за которую террористам удастся сделать сеть городов несвязной.

 

Пример входа

roads

{"0911",

 "9011",

 "1109",

 "1190"}

{"030900",

 "304120",

 "040174",

 "911021",

 "027207",

 "004170"}

{"0399",

 "3033",

 "9309",

 "9390"}

 

Пример выхода

4

8

9

 

 

РЕШЕНИЕ

максимальный поток

 

Рассмотрим граф, в котором города являются вершинами, а двусторонние дороги – неориентированными ребрами. По условию задачи в графе необходимо удалить такое множество ребер, суммарная стоимость которых наименьшая. Это классическая задача о минимальном разрезе. В то же время известно, что минимальный разрез графа равен максимальному потоку. Для любого разреза нулевая вершина будет отделена от какой-нибудь другой. Поэтому находим максимальный поток между нулевой и i - ой (0 < i < n = |V|) вершиной и среди всех значений найденных потоков находим наименьшее.

Функция mincut(s, t) находит величину максимального потока между вершинами s и t. Функция aug(x, t, CurFlow) находит пропускную способность дополняющего пути от вершины x до t, если известно, что пропускная способность дополняющего пути от начальной вершины до x равна CurFlow.

 

ПРОГРАММА

 

#include <cstdio>

#include <vector>

#include <string>

using namespace std;

 

int cap[50][50], res[50][50], used[50], n;

 

struct Terrorists

{

public:

  int aug(int x,int t,int CurFlow)

  {

    if (x == t) return CurFlow;

    if (used[x]++) return 0;

 

    for (int Flow, y = 0; y < n; y++)

    {

      if (res[x][y] > 0 && (Flow = aug(y,t,min(CurFlow,res[x][y]))))

      {

        res[x][y] -= Flow; res[y][x] += Flow;

        return Flow;

      }

    }

    return 0;

  }

 

  int mincut(int s, int t)

  {

    memcpy(res, cap, sizeof(cap));

    int x, flow = 0;

    do

    {

      memset(used,0,sizeof(used));

    } while ((x = aug(s,t,0x7FFFFFFF)) && (flow += x));

    return flow;

  }

 

  int requiredCost(vector<string> roads)

  {

    n = roads.size();

    for (int i = 0; i < n; i++)

      for (int j = 0; j < n; j++)

        cap[i][j] = roads[i][j] - '0';

 

    int best = 0x7FFFFFFF;

    for (int s = 1; s < n; s++)

      best = min(best,mincut(0, s));

    return best;    

  }

};